package org.gpslw.util;

import lombok.extern.slf4j.Slf4j;
import org.geotools.api.data.FeatureWriter;
import org.geotools.api.data.Transaction;
import org.geotools.api.feature.simple.SimpleFeature;
import org.geotools.api.feature.simple.SimpleFeatureType;
import org.geotools.api.feature.type.PropertyDescriptor;
import org.geotools.data.postgis.PostgisNGDataStoreFactory;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.store.ContentFeatureCollection;
import org.geotools.data.store.ContentFeatureSource;
import org.geotools.jdbc.JDBCDataStore;
import org.geotools.jdbc.JDBCDataStoreFactory;
import org.geotools.jdbc.JDBCFeatureStore;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.util.*;

@Slf4j
public final class DataStoreUtils {


    public static JDBCDataStore POST_GIS_DATA_STORE = null;

    public static JDBCDataStore getDataStore(DataSource dataSource) {
        if (POST_GIS_DATA_STORE != null) {
            return POST_GIS_DATA_STORE;
        } else {
            Map<String, Object> params = new HashMap<>();
            /**
             * 通过Datasource配置，以下配置可以不用了
             *             params.put(JDBCDataStoreFactory.DATABASE.key, "postgis_35_sample");
             *             params.put(JDBCDataStoreFactory.DBTYPE.key, "postgis");
             *             params.put(JDBCDataStoreFactory.HOST.key, "localhost");
             *             params.put(JDBCDataStoreFactory.PORT.key, "5432");
             *             params.put(JDBCDataStoreFactory.USER.key, "postgres");
             *             params.put(JDBCDataStoreFactory.PASSWD.key, "wismap");
             *             params.put(JDBCDataStoreFactory.DBTYPE.key, "postgis");
             */
            params.put(JDBCDataStoreFactory.EXPOSE_PK.key, true);
            params.put(JDBCDataStoreFactory.SCHEMA.key, "geoserver");
            params.put(JDBCDataStoreFactory.DATASOURCE.key, dataSource);

            try {

                POST_GIS_DATA_STORE = new PostgisNGDataStoreFactory().createDataStore(params);
            } catch (IOException e) {
                log.info("DataStoreUtils getDataStore error");
            }
        }
        return POST_GIS_DATA_STORE;
    }

    public static ShapefileDataStore getShapefileDataStore(String shpPath) {
        ShapefileDataStore shpDataStore = null;
        try {
            ShapefileDataStoreFactory shapefileDataStoreFactory = new ShapefileDataStoreFactory();
            Map<String, Object> params = new HashMap<>();
            params.put(shapefileDataStoreFactory.URLP.key, new File(shpPath).toURI().toURL());
            params.put(shapefileDataStoreFactory.MEMORY_MAPPED.key, true);
            params.put(shapefileDataStoreFactory.CACHE_MEMORY_MAPS.key, true);
            params.put(shapefileDataStoreFactory.DBFCHARSET.key, "utf-8");
            params.put(shapefileDataStoreFactory.DBFTIMEZONE.key, "Asia/Shanghai");
            params.put(shapefileDataStoreFactory.ENABLE_SPATIAL_INDEX.key, true);
            params.put(shapefileDataStoreFactory.SKIP_SCAN.key, true);
            shpDataStore = (ShapefileDataStore) shapefileDataStoreFactory.createNewDataStore(params);
        } catch (Exception e) {
            log.info("DataStoreUtils getShapefileDataStore error");
        }
        return shpDataStore;
    }


    /**
     * 根据shape文件路径获取SimpleFeature数据
     *
     * @param shpPath
     * @return
     */
    public static List<SimpleFeature> getShpData(String shpPath) {
        List<SimpleFeature> featureList = new ArrayList<>();
        ShapefileDataStore shapefileDataStore = getShapefileDataStore(shpPath);
        if (shapefileDataStore != null) {
            ContentFeatureSource featureSource = null;
            try {
                featureSource = shapefileDataStore.getFeatureSource();
                ContentFeatureCollection features = featureSource.getFeatures();
                SimpleFeatureIterator featureIterator = features.features();
                while (featureIterator.hasNext()) {
                    SimpleFeature feature = featureIterator.next();
                    featureList.add(feature);
                }
                featureIterator.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            shapefileDataStore.dispose();
        }
        return featureList;
    }


    /**
     * 将Shapefile数据导入到PostGIS数据库中
     *
     * @param shpPath       Shapefile的路径
     * @param jdbcDataStore 数据库连接对象，用于与PostGIS交互
     */
    public static void shpToPostGis(String shpPath, JDBCDataStore jdbcDataStore) {
        // 从Shapefile路径中读取数据
        List<SimpleFeature> shpData = getShpData(shpPath);
        // 检查Shapefile数据是否为空
        if (!CollectionUtils.isEmpty(shpData)) {
            // 获取数据类型名称
            String typeName = shpData.get(0).getFeatureType().getTypeName();
            try {
                // 获取数据库中的所有类型名称
                String[] typeNames = jdbcDataStore.getTypeNames();
                // 检查数据库中是否已存在该类型，如果不存在则创建
                if (!Arrays.asList(typeNames).contains(typeName)) {
                    jdbcDataStore.createSchema(shpData.get(0).getFeatureType());
                }
                // 获取数据库中的Schema
                SimpleFeatureType featureType = jdbcDataStore.getSchema(typeName);
                // 获取FeatureWriter对象，用于向数据库中添加数据
                FeatureWriter<SimpleFeatureType, SimpleFeature> featureWriter = jdbcDataStore.getFeatureWriterAppend(typeName,
                        Transaction.AUTO_COMMIT);
                // 初始化第一个Feature对象
                SimpleFeature nexSimpleFeature = featureWriter.next();
                // 遍历Shapefile数据，将每个Feature对象的属性值设置到数据库中的Feature对象
                for (SimpleFeature shpDatum : shpData) {
                    // 获取FeatureType的所有属性描述符
                    Collection<PropertyDescriptor> descriptors = featureType.getDescriptors();
                    // 遍历属性描述符，设置每个属性的值
                    for (PropertyDescriptor descriptor : descriptors) {
                        nexSimpleFeature.setAttribute(descriptor.getName(), shpDatum.getAttribute(descriptor.getName()));
                    }
                    // 写入当前Feature对象
                    featureWriter.write();
                    // 获取下一个Feature对象
                    nexSimpleFeature = featureWriter.next();
                }
                // 关闭FeatureWriter和数据库连接
                featureWriter.close();
            } catch (IOException e) {
                // 抛出运行时异常，包装IOException
                throw new RuntimeException(e);
            }
        }
    }


    /**
     * 将Shapefile数据导入到PostGIS数据库中
     *
     * @param shpPath       Shapefile的路径
     * @param jdbcDataStore 数据库连接对象，用于与PostGIS交互
     */
    public static void shpToPostGisV2(String shpPath, JDBCDataStore jdbcDataStore) {
        // 从Shapefile路径中读取数据
        List<SimpleFeature> shpData = getShpData(shpPath);
        // 检查Shapefile数据是否为空
        if (!CollectionUtils.isEmpty(shpData)) {
            // 获取数据类型名称
            String typeName = shpData.get(0).getFeatureType().getTypeName();
            try {
                // 获取数据库中的所有类型名称
                String[] typeNames = jdbcDataStore.getTypeNames();
                // 检查数据库中是否已存在该类型，如果不存在则创建
                if (!Arrays.asList(typeNames).contains(typeName)) {
                    jdbcDataStore.createSchema(shpData.get(0).getFeatureType());
                }
                // 直击获取FeatureStore对象（是FeatureSource的子对象）
                JDBCFeatureStore featureSource = (JDBCFeatureStore) jdbcDataStore.getFeatureSource(typeName, Transaction.AUTO_COMMIT);
                //批量保存，不通过featureWriter对象保存的形式
                featureSource.addFeatures(shpData);
            } catch (IOException e) {
                // 抛出运行时异常，包装IOException
                throw new RuntimeException(e);
            }
        }
    }

}
